package com.hyt.it.ogt.ks.job;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.common.base.Stopwatch;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.it.ogt.ks.config.ConfigManager;
import com.hyt.it.ogt.ks.enums.BizStatusCode;
import com.hyt.it.ogt.ks.feign.KwClient;
import com.hyt.it.ogt.ks.feign.model.EndExamCandidaeDTO;
import com.hyt.it.ogt.ks.service.ICandidateAnswerBackupService;
import com.hyt.it.ogt.ks.util.DateUtil;
import com.hyt.it.ogt.ks.util.KeyDefineCommon;
import com.hyt.it.ogt.ks.util.LocalDateTimeUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * @author wuyingge
 * @ClassName CandidateAnswerBackupTask.java
 * @Description 考生定时任务处理
 * @createTime 2021年11月22日 15:09:00
 */
@Component
@Slf4j
public class CandidateAnswerBackupTask {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private KwClient kwClient;
    @Resource
    private ConfigManager configManager;
    @Resource
    private ICandidateAnswerBackupService iCandidateAnswerBackupService;

    //@Scheduled(cron = "0 0 1 * * ?")
    public void backupAnswer(){
        String key = KeyDefineCommon.getCandidateAnswerBakcupKey(LocalDateTimeUtils.formatTime(LocalDateTime.now(),LocalDateTimeUtils.YYYYMMDD));
        if(!redisTemplate.opsForValue().setIfAbsent(key,1)
                || Objects.equals(0,configManager.getCandidateAnswerBackupEnable())){
            return;
        }
        log.info("考生试题移动至备份库定时任务启动:,启动时间为:【{}】", DateUtil.date2String(LocalDateTime.now()));
        try {
            //1:查询kw判断有多少考生完成考试及判分
            String ecCountRsp = kwClient.getEndExamCandidateCount(EndExamCandidaeDTO.builder().backupType(1).build());
            log.info("查询考务完成考试及判分考生总数返回信息为:【{}】",ecCountRsp);
            if(StringUtils.isBlank(ecCountRsp)){
                log.error("考生试题移动至备份库定时任务查询完成考试考生信息失败");
                return;
            }
            ApiResponse<Integer> ecResponse = ApiResponse.ConvertRet(ecCountRsp,Integer.class);
            if(!Objects.equals(BizStatusCode.KW_SUCCESS_OK.getCode(),ecResponse.getCode()) || Objects.isNull(ecResponse.getData())){
                log.error("考生试题移动至备份库定时任务查询完成考试考生信息失败,返回信息为:【{}】",ecResponse);
                return;
            }
            //分页进行查询，分批次发送消息
            Integer count = ecResponse.getData();
            if(count < 1){
                log.info("考生试题移动至备份库定时任务完成,原因为当前没有符合移动数据的考生");
                redisTemplate.delete(key);
                return;
            }
            Integer size = configManager.getCandidateAnswerBackupSize();
            Integer pageTotal = 0;//总的次数
            if (count % size == 0) {
                pageTotal = count / size;
            } else {
                pageTotal = count / size + 1;
            }
            // 计时器
            Stopwatch mainThread = Stopwatch.createStarted();
            //线程池 当前批次的数量可控制不用担心队列等待数量过大的问题
            final ExecutorService threadPool = Executors.newFixedThreadPool(pageTotal, r -> {
                Thread t = new Thread(r);
                t.setName("考生试题移动至备份库定时任务" + t.getId());
                return t;
            });
            //线程计数器
            final CountDownLatch countDownLatch = new CountDownLatch(pageTotal);//总共有多少任务要处理

            for(int i = 1 ; i <= pageTotal; i++ ){
                final Integer current = i;
                //调用kw查询符合条件的考生
                String ecRep = kwClient.getEndExamCandidateIds(EndExamCandidaeDTO.builder().size(size).current(i).backupType(1).build());
                if(StringUtils.isBlank(ecRep)){
                    log.error("考生试题移动至备份库定时任务查询符合条件的考生失败，第:【{}】页",i);
                    continue;
                }
                ApiResponse<JSONArray> resResponse = JSON.parseObject(ecRep, ApiResponse.class);
                if(!Objects.equals(BizStatusCode.KW_SUCCESS_OK.getCode(),resResponse.getCode()) || Objects.isNull(resResponse.getData())){
                    log.error("考生试题移动至备份库定时任务查询符合条件的考生失败，第:【{}】页,返回的失败信息为:【{}】",i,resResponse);
                    continue;
                }
                List<String> ecIds = JSON.parseArray(resResponse.getData().toString(),String.class);
                //提交任务至线程池
                threadPool.submit(() -> {
                    try {
                        log.info("考生试题移动至备份库定时任务第:【{}】提交给线程池。",current);
                        //计时器
                        Stopwatch jobThread = Stopwatch.createStarted();
                        //执行目标任务
                        iCandidateAnswerBackupService.moveAnswerToBackup(ecIds.toArray(new String[0]));
                        log.info("考生试题移动至备份库定时任务第:【{}】提交给线程池完成，耗时【{}】。",current,jobThread.elapsed(TimeUnit.SECONDS));
                    } catch (Exception e){
                        log.error("考生试题移动至备份库定时任务第:【{}】提交给线程池,发生异常:【】。",current,e);
                    } finally {
                        countDownLatch.countDown();
                    }
                });
            }
            //等待所有的线程完成，记录当前失败的任务
            countDownLatch.await();
            threadPool.shutdown();

            log.info("考生试题移动至备份库定时任务线程池任务全部完成，共耗时【{}】秒",mainThread.elapsed(TimeUnit.SECONDS));
            redisTemplate.delete(key);
        } catch (Exception e){
            log.error("考生试题移动至备份库定时任务提交任务至线程池发生异常，异常信息为:",e);

        } finally {
            redisTemplate.delete(key);
        }

    }
}
